﻿using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Web;

namespace YuYuKiCms.Framework.Extention
{
    public static class StringExtensions
    {
        public static string RemoveDiacritics(this string text)
        {
            var normalizedString = text.Normalize(NormalizationForm.FormD);
            var sb = new StringBuilder();
            foreach (var c in normalizedString)
            {
                var unicodeCategory = CharUnicodeInfo.GetUnicodeCategory(c);
                if (unicodeCategory != UnicodeCategory.NonSpacingMark)
                {
                    sb.Append(c);
                }
            }
            return sb.ToString().Normalize(NormalizationForm.FormC);
        }

        public static string EscapeJsonForFormat(this string source)
        {
            return source.Replace("{", "{{").Replace("}", "}}");
        }

        public static string ToBase64(this string source)
        {
            var buffer = Encoding.UTF8.GetBytes(source);
            return Convert.ToBase64String(buffer);
        }

        public static string FromBase64(this string source)
        {
            var buffer = Convert.FromBase64String(source);
            return Encoding.UTF8.GetString(buffer);
        }

        public static string ToBase64Url(this string source)
        {
            return source.ToBase64().UrlEncode();
        }

        public static string FromBase64Url(this string source)
        {
            return source.UrlDecode().FromBase64();
        }

        public static string UrlEncode(this string data)
        {
            return HttpUtility.UrlEncode(data);
        }

        public static string UrlDecode(this string data)
        {
            return HttpUtility.UrlDecode(data);
        }

        public static IDictionary<string, string> ParseQueryString(this string uri)
        {
            return new Uri(uri).ParseQueryString();
        }

        public static IDictionary<string, string> ParseQueryString(this Uri uri)
        {
            return uri.Query.ParseQueryStringCore()
                .ToDictionary(k => k.Key, v => v.Value, new CaseInsensitiveStringEqualityComparer());
        }

        private static IEnumerable<KeyValuePair<string, string>> ParseQueryStringCore(this string query)
        {
            if (String.IsNullOrEmpty(query)) return Enumerable.Empty<KeyValuePair<string, string>>();
            return query.Substring(1) // remove '?' character from querystring
                .Split(new[] {'&'}, StringSplitOptions.RemoveEmptyEntries) // split on '&' to retrieve all parameters
                .Select(keyValuePair => keyValuePair.Split('='))
                // split on '=' to have the parameter name and parameter value
                .Where(pair => pair.Length == 2) // only key the element which are true key-value-pair
                .Select(pair => new KeyValuePair<string, string>(pair[0], pair[1]));
        }

        public static DateTime ToDateTime(this string dateString)
        {
            return DateTime.ParseExact(dateString, "d/M/yyyy", CultureInfo.InvariantCulture);
        }

        /// <summary>
        ///     Convert a string to a DateTime
        ///     The date format is dd/MM/yyyy
        /// </summary>
        /// <param name="dateStr"></param>
        /// <returns>null if fail otherwise return a dateTime</returns>
        public static DateTime? ParseDateExact(this string dateStr)
        {
            if (string.IsNullOrWhiteSpace(dateStr))
                return null;

            DateTime date;

            if (!DateTime.TryParseExact(dateStr, "dd/MM/yyyy",
                CultureInfo.InvariantCulture, DateTimeStyles.None,
                out date))
                return null;

            return date;
        }

        private class CaseInsensitiveStringEqualityComparer : EqualityComparer<string>
        {
            /// <summary>
            ///     When overridden in a derived class, determines whether two objects of type <see cref="T:System.String" /> are
            ///     equal.
            /// </summary>
            /// <returns>
            ///     true if the specified objects are equal; otherwise, false.
            /// </returns>
            /// <param name="x">The first object to compare.</param>
            /// <param name="y">The second object to compare.</param>
            public override bool Equals(string x, string y)
            {
                return String.Equals(x, y, StringComparison.OrdinalIgnoreCase);
            }

            /// <summary>
            ///     When overridden in a derived class, serves as a hash function for the specified object for hashing algorithms and
            ///     data structures, such as a hash table.
            /// </summary>
            /// <returns>
            ///     A hash code for the specified object.
            /// </returns>
            /// <param name="obj">The object for which to get a hash code.</param>
            /// <exception cref="T:System.ArgumentNullException">
            ///     The type of <paramref name="obj" /> is a reference type and
            ///     <paramref name="obj" /> is null.
            /// </exception>
            public override int GetHashCode(string obj)
            {
                if (obj == null) return 0;
                return obj.ToLower().GetHashCode();
            }
        }
    }
}